package com.shuang.graph14;

//import java.util.*;
////prim算法
//public class Main {
//    public static void main(String[] args) {
//        Scanner scanner = new Scanner(System.in);
//        int v = scanner.nextInt();
//        int e = scanner.nextInt();
//
//        // 初始化邻接矩阵，所有值初始化为一个大值，表示无穷大
//        int[][] grid = new int[v + 1][v + 1];
//        for (int i = 0; i <= v; i++) {
//            Arrays.fill(grid[i], 10001);
//        }
//
//        // 读取边的信息并填充邻接矩阵
//        for (int i = 0; i < e; i++) {
//            int x = scanner.nextInt();
//            int y = scanner.nextInt();
//            int k = scanner.nextInt();
//            grid[x][y] = k;
//            grid[y][x] = k;
//        }
//
//        //用于记录该节点是否被加入到了生成树中
//        boolean[] isTree = new boolean[v + 1];
//
//        // 所有节点到最小生成树的最小距离
//        int[] minDist = new int[v + 1];
//
//        //所有值初始化为一个大值
//        Arrays.fill(minDist, 10001);
//
//        //prim算法主循环 有三部
//        //遍历n-1条边
//        for (int i = 1; i < v; i++){
//
//            //用于记录当前取到的距离生成树最近的节点（要加入生成树中的节点）
//            int cur = -1;
//
//            //用于找最小值 先初始化最大值
//            int minValue = Integer.MAX_VALUE;
//
//            //1 遍历所有节点找到距离生成树最近的节点
//            for (int j = 1; j <= v; j++){
//                if (!isTree[j] && minDist[j] < minValue){
//                    cur = j;
//                    minValue = minDist[j];
//                }
//            }
//
//            //2 将距离最近的节点加入到生成树中
//            isTree[cur] = true;
//
//            //3 更新所有非生成树到生成树的距离
//            for (int j = 1; j <= v; j++){
//                if (!isTree[j] && grid[cur][j] < minDist[j]){
//                    minDist[j] = grid[cur][j];
//                }
//            }
//        }
//
//
//        // 统计结果
//        int result = 0;
//        for (int i = 2; i <= v; i++) {
//            result += minDist[i];
//        }
//        System.out.println(result);
//        scanner.close();
//    }
//}

import java.util.*;
//kruskal算法
class Edge {
    int l, r, val;

    Edge(int l, int r, int val) {
        this.l = l;
        this.r = r;
        this.val = val;
    }
}

public class Main {
    private static int n = 10001;
    private static int[] father = new int[n];

    // 并查集初始化
    public static void init() {
        for (int i = 0; i < n; i++) {
            father[i] = i;
        }
    }

    // 并查集的查找操作
    public static int find(int u) {
        if (u == father[u]) return u;
        return father[u] = find(father[u]);
    }

    // 并查集的加入集合
    public static void join(int u, int v) {
        u = find(u);
        v = find(v);
        if (u == v) return;
        father[v] = u;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int v = scanner.nextInt();
        int e = scanner.nextInt();
        List<Edge> edges = new ArrayList<>();
        int result_val = 0;

        for (int i = 0; i < e; i++) {
            int v1 = scanner.nextInt();
            int v2 = scanner.nextInt();
            int val = scanner.nextInt();
            edges.add(new Edge(v1, v2, val));
        }

        // 执行Kruskal算法
        edges.sort(Comparator.comparingInt(edge -> edge.val));

        // 并查集初始化
        init();

        // 从头开始遍历边
        for (Edge edge : edges) {
            int x = find(edge.l);
            int y = find(edge.r);

            if (x != y) {
                result_val += edge.val;
                join(x, y);
            }
        }
        System.out.println(result_val);
        scanner.close();
    }